package findEnsemble;

import genetic_algorithm.Chromosome;
import genetic_algorithm.FitnessFunction;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.Vector;

import mlp.Mlp;
import utils.VectorClassificationPair;

public class FindEnsembleFitness implements FitnessFunction {
	
	private static final String RESULTS_FILE = "find_ensemble_results.txt";
	
	static List<VectorClassificationPair > testData; // a test example (float array) and its result of the test data
	Vector<Vector <float[]>> testResults; // output of each network on each test example : testResult.get(digit).get(#network)[#example]
	
	static public void initTestData(String testSetFileName)	{
		
		Scanner scan = null;
		try {
			scan = new Scanner(new File(testSetFileName));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}

		testData = new ArrayList<VectorClassificationPair>();
		String line;
		int cls;
		while(scan.hasNext()) {
			
			line = scan.nextLine();
			cls = Integer.parseInt(line.substring(0,1));
			String[] inputsStr = line.substring(2).split(",");
			float[] inputs = new float[inputsStr.length];
			for(int i =0 ; i < inputsStr.length ; i++){inputs[i] = Float.parseFloat(inputsStr[i]);}
			testData.add(new VectorClassificationPair(inputs, cls));
		}
		scan.close();
	}
	
	@SuppressWarnings("unchecked")
	public FindEnsembleFitness(List<List<Mlp>> mlps) {

		try {
			FileInputStream readFile = new FileInputStream(RESULTS_FILE);
			ObjectInputStream fileStream = new ObjectInputStream(readFile);
			testResults = ((Vector<Vector <float[]>>) fileStream.readObject());
			fileStream.close();
		} catch (FileNotFoundException e) {	
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	@Override
	public double getFitness(Chromosome chromosome) {

		double success = 0;
		for(int exampleIndex = 0 ; exampleIndex < testData.size() ; exampleIndex++)
		{
			if(getClassification(exampleIndex, ((FindEnsembleChromosome)chromosome).getAllIndices()) == testData.get(exampleIndex).getClassification())
			{
				success++;
			}	
		}
		return (success/testData.size())*100.0;
	}

	private int getClassification(int testExamIndex, List<Integer> mlps) {
		
		// get result of each network for example matching given index
		float[] results = {0,0,0,0,0,0,0,0,0,0}; // i'th value is result of network recognizing digit i
		for(int digit = 0 ; digit < FindEnsembleMain.NUM_CLASSES ; ++digit) {
			results[digit] = testResults.get(digit).get(mlps.get(digit))[testExamIndex]; // get result of each network
		}
		
		// return classification as index of maximal value
		int max = 0;
		for(int i = 1; i < FindEnsembleMain.NUM_CLASSES ; ++i) {
			max = results[max]>=results[i] ? max : i;
		}
		return max;		
	}
}
